#include "HerzeleidPrecompiled.hxx"

#include "HerzeleidPointerPointProperties.hxx"
#include "HerzeleidCoreDispatcher.hxx"
#include "HerzeleidPointerPoint.hxx"
#include "HerzeleidVirtualKey.hxx"

using namespace HerzeleidSystemNamespaceImpl;
using namespace HerzeleidUICoreNamespaceImpl;
using namespace HerzeleidUIInputNamespaceImpl;
using namespace HerzeleidFoundationNamespaceImpl;

#define HerzeleidIsBarrelButtonPressed( Flags ) (Flags & PEN_FLAG_BARREL)
#define HerzeleidIsInverted( Flags ) (Flags & PEN_FLAG_INVERTED)
#define HerzeleidIsEraser( Flags ) (Flags & PEN_FLAG_ERASER)

PointerPoint::PointerPoint(): 
	m_Properties(),
	m_RawPosition( Point::Empty() ),
	m_Position( Point::Empty() ),
	m_bIsInContact( false ),
	m_uTimestamp64( 0 ), 
	m_uPointerId( 0 ), 
	m_uFrameId( 0 )
{
}

#ifndef GET_X_LPARAM
#define GET_X_LPARAM(lp)                        ((int)(short)LOWORD(lp))
#endif
#ifndef GET_Y_LPARAM
#define GET_Y_LPARAM(lp)                        ((int)(short)HIWORD(lp))
#endif

Void PointerPoint::Configure( WindowMessage Msg, PointerUpdateKind Kind )
{
	m_Properties.m_ePointerUpdateKind = Kind;
	m_Properties.m_ContantRect.X = m_Properties.m_ContantRectRaw.X = m_Position.X = m_RawPosition.X = 
		static_cast<Float32>(GET_X_LPARAM( Msg.LParam ));
	m_Properties.m_ContantRect.Y = m_Properties.m_ContantRectRaw.Y = m_Position.Y = m_RawPosition.Y = 
		static_cast<Float32>(GET_Y_LPARAM( Msg.LParam ));

	if ( Msg.WParam & MK_LBUTTON )	m_Properties.m_ePointerUpdateKind |= PointerUpdateKind::LeftButtonPressed;
	if ( Msg.WParam & MK_RBUTTON )	m_Properties.m_ePointerUpdateKind |= PointerUpdateKind::RightButtonPressed;
	if ( Msg.WParam & MK_MBUTTON )	m_Properties.m_ePointerUpdateKind |= PointerUpdateKind::MiddleButtonPressed;
	if ( Msg.WParam & MK_XBUTTON1 )	m_Properties.m_ePointerUpdateKind |= PointerUpdateKind::XButton1Pressed;
	if ( Msg.WParam & MK_XBUTTON2 )	m_Properties.m_ePointerUpdateKind |= PointerUpdateKind::XButton2Pressed;

	//if ( !(Bool)(Kind) ) switch ( Msg.Message )
	if ( Kind == PointerUpdateKind::Other ) switch ( Msg.Message )
	{
	case WM_MOUSEHWHEEL: m_Properties.m_bTiltMouseWheel = true; // Indicate we are using tilt wheel. 
	case WM_MOUSEWHEEL: m_Properties.m_iMouseWheelDelta = GET_WHEEL_DELTA_WPARAM(Msg.WParam); break; // Get mouse wheel delta. 
	}
}

Void PointerPoint::Configure( WindowMessage Msg, RawPointerInfoPtr PointerInfo )
{	
	//auto PointerId = GET_POINTERID_WPARAM(Msg.WParam);
	m_Position.X = m_RawPosition.X = static_cast<Float32>(GET_X_LPARAM( Msg.LParam ));
	m_Position.Y = m_RawPosition.Y = static_cast<Float32>(GET_Y_LPARAM( Msg.LParam ));
	m_bIsInContact = IS_POINTER_INCONTACT_WPARAM(Msg.WParam);
	m_Properties.m_bIsInRange = IS_POINTER_INRANGE_WPARAM(Msg.WParam);
	m_Properties.m_bPrimary = IS_POINTER_PRIMARY_WPARAM(Msg.WParam);
	if (!PointerInfo) return;

	m_uFrameId = PointerInfo->frameId;
	m_RawPosition.X = static_cast<Float32>(PointerInfo->ptPixelLocationRaw.x);
	m_RawPosition.Y = static_cast<Float32>(PointerInfo->ptPixelLocationRaw.y);
	m_Position.X = static_cast<Float32>(PointerInfo->ptPixelLocation.x);
	m_Position.Y =static_cast<Float32>(PointerInfo->ptPixelLocation.y);
	m_Properties.m_ePointerUpdateKind = (PointerUpdateKind)(PointerInfo->ButtonChangeType);

	if ( PointerInfo->pointerFlags & POINTER_FLAG_INCONTACT )
	{
		m_bIsInContact = true;
	}
	if ( PointerInfo->pointerFlags & POINTER_FLAG_WHEEL )
	{
		m_Properties.m_iMouseWheelDelta =  PointerInfo->InputData;
	}
	else if ( PointerInfo->pointerFlags & POINTER_FLAG_HWHEEL )
	{
		m_Properties.m_iMouseWheelDelta =  PointerInfo->InputData;
		m_Properties.m_bTiltMouseWheel = true;
	}

	m_uPointerId = PointerInfo->pointerId;
	m_uTimestamp64 = PointerInfo->dwTime;

	switch (PointerInfo->pointerType)
	{
    case PT_TOUCH:  
		{
			POINTER_TOUCH_INFO TouchInfo;
			if (GetPointerTouchInfo(m_uPointerId, &TouchInfo))
			{
				m_Properties.m_fPressure = ((Float32)TouchInfo.pressure) / 1024.f;
				m_Properties.m_fOrientation = ((Float32)TouchInfo.orientation);
				m_Properties.m_ContantRectRaw = TouchInfo.rcContactRaw;
				m_Properties.m_ContantRect = TouchInfo.rcContact;
			}
		} break;   // Touch
    case PT_PEN:   
		{
			POINTER_PEN_INFO PenInfo;
			if (GetPointerPenInfo(m_uPointerId, &PenInfo))
			{
				m_Properties.m_bIsBarrelButtonPressed = HerzeleidIsBarrelButtonPressed(PenInfo.penFlags) ? true : false;
				m_Properties.m_bIsInverted = HerzeleidIsInverted(PenInfo.penFlags) ? true : false;
				m_Properties.m_fPressure = ((Float32)PenInfo.pressure) / 1024.f;
				m_Properties.m_bIsEraser = HerzeleidIsEraser(PenInfo.penFlags) ? true : false;
				m_Properties.m_fTwist = ((Float32)PenInfo.rotation);
				m_Properties.m_fXTilt = ((Float32)PenInfo.tiltX);
				m_Properties.m_fYTilt = ((Float32)PenInfo.tiltY);
			}
		} break;  // Pen
	}
}